#include "Common.h"

initSing(LuaManager);

void _registerHook(ui32 type, const char* fname)
{
	if(type < 0 || type >= NUM_HOOKS)
	{
		Log->Error("LuaEngine", "Called _registerHook with an incorrect HookType (needs to be between 0 and %u", NUM_HOOKS - 1);
		return;
	}
	sLuaHook.RegisterHook(type, fname);
}

int _formatString(lua_State* lstate)
{
	int param = lua_gettop(lstate);
	if(!param)
		return 0;
	stringstream strm;
	for(int i = 1; i <= param; ++i)
	{
		if(lua_isnumber(lstate, i))
			strm << lua_tointeger(lstate, i);
		else if(lua_isstring(lstate, i))
			strm << lua_tostring(lstate, i);
		else if(lua_isboolean(lstate, i))
			strm << lua_toboolean(lstate, i) ? "true" : "false";
		else if(lua_isnil(lstate, i))
			strm << "(nil)";
	}
	lua_pushstring(lstate, strm.str().c_str());
	return 1;
}

int _registerUnitGossipFunc(lua_State* lstate)
{
	int param = lua_gettop(lstate);
	if(param != 3)
	{
		Log->Error("LUAEngine", "Called RegisterGossipHello with incorrect paramcount (%u instead of 3)", param);
		return 0;
	}
	
	if(!lua_isnumber(lstate, 1) || !lua_isnumber(lstate, 2) || !lua_isstring(lstate, 3))
	{
		Log->Error("LUAEngine", "Incorrect params! (needs to be type - entry - functionname)");
		return 0;
	}

	int type = lua_tointeger(lstate, 1);
	int entry = lua_tointeger(lstate, 2);
	string func = lua_tostring(lstate, 3);
	LuaManager::getSingle()->RegisterUnitGossip(type, entry, func);
}

LuaManager::LuaManager()
{
	l = LuaInterface::QueryState();
	new LuaHookMgr(l);
	sScriptMgr->register_hook(LuaHookMgr::getSingle());
	LuaInterface::OpenBaseLib(l);
	open(l);
}

LuaManager::~LuaManager()
{
	lua_close(l);
}

#define lua_registerglobal(state, value, name) lua_pushnumber(state, value); lua_setglobal(state, name);

void LuaManager::Load()
{
	module(l)
	[
		LUAPlayer::RegisterLUAPlayer(),
		LUAUnit::RegisterLUAUnit(),
		LUAMoney::RegisterLUAMoney(),
		LUAColor::RegisterLUAColor(),
		LUAVector::RegisterLUAVector(),
		LUALog::RegisterLUALog(),
		LUAPacket::RegisterLUAPacket(),

		namespace_("Useable")
		[
			def("GetDistance", (float (*)(float, float, float, float, float, float))&Useable::GetDistance)
		]
	];
	module(l)
	[
		def("RegisterHook", &_registerHook)
	];

	lua_registerglobal(l, UNIT_FIELD_FACTIONTEMPLATE, "UNIT_FIELD_FACTIONTEMPLATE");

	lua_register(l, "FormatString", _formatString);
	lua_register(l, "RegisterUnitGossip", _registerUnitGossipFunc);

	char dire[MAX_PATH];
	GetCurrentDirectory(MAX_PATH, dire);
	char new_path[MAX_PATH];
	strcpy(new_path, dire);
	strcat(dire, "\\Luascripts\\");
	SetCurrentDirectory(dire);
	WIN32_FIND_DATA wind;
	memset(&wind, 0, sizeof(wind));
	HANDLE hFile = FindFirstFile("*.lua", &wind);
	printf("\n\n");
	Log->Notice("LUAEngine", "Loading scripts...\n");
	if(hFile == INVALID_HANDLE_VALUE)
	{
		SetCurrentDirectory(new_path);
		return;
	}

	do
	{
		Log->Notice("LUAEngine", "Loading script `%s`...", wind.cFileName);
		PrintStateError(LuaInterface::ParseFile(l, wind.cFileName));
	}
	while(FindNextFile(hFile, &wind));
	SetCurrentDirectory(new_path);
	printf("\n\n");
}

void LuaManager::PrintStateError(int retval)
{
	if(retval)
	{
		Log->Error("LuaEngine", "%s", lua_tostring(l, 1));
		lua_pop(l, 1);
	}
}

void LuaManager::OnGossipHello(Player* requester, Creature* sender)
{
	if(!sender || !requester)
		return;
	string func = m_gossiphello[sender->GetEntry()];
	if(!func.length())
		return;
	LUAUnit unit;
	unit.cr = sender;
	LUAPlayer plr;
	plr.plr = requester;
	try
	{
		call_function<LUAPlayer>(l, func.c_str(), plr, unit);
	}
	catch(error& e)
	{
		Log->Error("LUAEngine", "%s", e.what());
	}

}

void LuaManager::OnGossipSelect(Player* requester, Creature* sender, ui32 intid)
{
	if(!sender || !requester)
		return;
	string func = m_gossipselect[sender->GetEntry()];
	if(!func.length())
		return;
	LUAUnit unit;
	unit.cr = sender;
	LUAPlayer plr;
	plr.plr = requester;
	try
	{
		call_function<LUAPlayer>(l, func.c_str(), plr, unit, intid);
	}
	catch(error& e)
	{
		Log->Error("LUAEngine", "%s", e.what());
	}
}

void LuaManager::RegisterUnitGossip(ui32 type, ui32 entry, string& funcname)
{
	switch(type)
	{
	case 0:
		m_gossiphello[entry]= funcname;
		break;

	case 1:
		m_gossipselect[entry] = funcname;
		break;
	}
}